#include "StdAfx.h"
#include "OsuFile.h"
#include <fstream>
#include <sstream>

//-----------------------------------------------------------------------------
void OsuFile::reset()
{
	audioFilename.			resize(0);
	videoFilename.			resize(0);
	backgroundFilename.	resize(0);
	breakPeriods.			resize(0);
	comboColors.			resize(0);
	hitObjects.				resize(0);
	timingPoints.			resize(0);

	metadata.title.		resize(0);
	metadata.artist.		resize(0);
	metadata.creator.		resize(0);
	metadata.version.		resize(0);
	metadata.source.		resize(0);
	metadata.tags.			resize(0);

	audioLeadIn				= 0;
	videoStartTime			= 0;
	previewTime				= 0;
	countdown				= 0;
	overallDifficulty		= 0;
	sliderMultiplier		= 0;
}

//-----------------------------------------------------------------------------
void OsuFile::readOsuFile(LPCWSTR filename)
{
	reset();

	std::wifstream file(filename);

	if(!file.is_open())
		return;

//	count number of lines
//	int lines = std::count(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>(), '\n'));
//	file.seekg(std::ios_base::beg);

	std::wstring buffer;

	enum Chunk
	{
		General = 0,
		Editor,
		Metadata	,
		Difficulty,
		Events,
		TimingPoints,
		Colours,
		HitObjects,
		Undefined
	};

	static const
	std::wstring	ChunkStrings[8] = {L"[General]",L"[Editor]",L"[Metadata]",L"[Difficulty]",L"[Events]",L"[TimingPoints]",L"[Colours]",L"[HitObjects]"},
						AudioFilename		(L"AudioFilename"),
						AudioLeadIn			(L"AudioLeadIn"),
						PreviewTime			(L"PreviewTime"),
						Countdown			(L"Countdown"),
						Title					(L"Title"),
						Artist				(L"Artist"),
						Creator				(L"Creator"),
						Version				(L"Version"),
						Source				(L"Source"),
						Tags					(L"Tags"),
						OverallDifficulty	(L"OverallDifficulty"),
						SliderMultiplier	(L"SliderMultiplier");

	Chunk chunk = Undefined;

//----
//	Read the file line by line
	while(!file.eof())
	{
		getline(file,buffer);

		if(buffer.size() == 0)
			continue;

	//----
	//	Beginning of new chunk?
		if(buffer[0]==L'[')
		{
			for(unsigned i = 0; i < 8; i++)
				if	(buffer == ChunkStrings[i])
				{
					chunk = (Chunk)i;
					break;
				}
		}
	//----
	//	Knowing the current chunk, reduces the necessary string comparisons, etc.
		else switch(chunk)
		{
			case General:
				if			(buffer.substr(0,13) == AudioFilename)		audioFilename		= buffer.substr(15, buffer.size()-15);
				else if	(buffer.substr(0,11) == AudioLeadIn)		audioLeadIn			= _wtoi(&buffer[13]);
				else if	(buffer.substr(0,11) == PreviewTime)		previewTime			= _wtoi(&buffer[13]);
				else if	(buffer.substr(0, 9) == Countdown)			countdown			= _wtoi(&buffer[11]);
			break;
			case Metadata:
				if			(buffer.substr(0, 5) == Title)				metadata.title		= buffer.substr(6, buffer.size()-6);
				else if	(buffer.substr(0, 6) == Artist)				metadata.artist	= buffer.substr(7, buffer.size()-7);
				else if	(buffer.substr(0, 7) == Creator)				metadata.creator	= buffer.substr(8, buffer.size()-8);
				else if	(buffer.substr(0, 7) == Version)				metadata.version	= buffer.substr(8, buffer.size()-8);
				else if	(buffer.substr(0, 6) == Source)				metadata.source	= buffer.substr(7, buffer.size()-7);
				else if	(buffer.substr(0, 4) == Tags)					metadata.tags		= buffer.substr(5, buffer.size()-5);
			break;
			case Difficulty:
				if			(buffer.substr(0,17) == OverallDifficulty)overallDifficulty	= _wtoi(&buffer[18]);
				else if	(buffer.substr(0,16) == SliderMultiplier)	sliderMultiplier	= convert<double>(buffer.substr(17,buffer.size()-17));
			break;
			case Events:
			//	type{0 = graphic, 1 or Video = video, 2 = break_period, 3 = colour_transformations},time_in_ms,"filename"
				if(buffer[0]==L'/')
					break;
				int type;
				if(buffer[0]==L'V')	type = 1;
				else						type = _wtoi(&buffer[0]);
				if(type==0 && buffer[0]!=L'0')
					break;
				if(type==0||type==1)			// graphics or video file
				{
					int												j = buffer.find_first_of(L',',0) + 1;
					int time = _wtoi(&buffer[j]);				j = buffer.find_first_of(L'"',j) + 1;
					std::wstring filename = buffer.substr(j, buffer.size()-j-1);

					if(type==0)
						backgroundFilename	= filename;
					else
					{
						videoFilename			= filename;
						videoStartTime			= time;
					}
				}
				else
				if(type==2)						// break period
				{
					BreakPeriod b;
					int												j = buffer.find_first_of(L',',0) + 1;
					b.start	= _wtoi(&buffer[j]);				j = buffer.find_first_of(L',',j) + 1;
					b.stop	= _wtoi(&buffer[j]);
					breakPeriods.push_back(b);
				}
				else
				if(type==3)						// background color transformation
				{
				}
			break;
			case TimingPoints:
				{
//					39364,-100,4,1,0,100,0,1
					TimingPoint t;
					int j = 0, j2;
					t.time		= _wtoi(&buffer[j]);			j = buffer.find_first_of(L',',j) + 1;
																		j2= buffer.find_first_of(L',',j) + 1;
					t.msPerBeat = convert<double>(buffer.substr(j,j2-j-1));
					if(t.msPerBeat < 0 && timingPoints.size())
						t.msPerBeat = -0.01 * t.msPerBeat * timingPoints[timingPoints.size()-1].msPerBeat;
					t.meter			= _wtoi(&buffer[j=j2]);	j = buffer.find_first_of(L',',j) + 1;
					t.sampleSet			= _wtoi(&buffer[j]);	j = buffer.find_first_of(L',',j) + 1;
					t.customOverride	= _wtoi(&buffer[j]);	j = buffer.find_first_of(L',',j) + 1;
					t.volume				= _wtoi(&buffer[j]);	j = buffer.find_first_of(L',',j) + 1;
					t.unknown			= _wtoi(&buffer[j]);	j = buffer.find_first_of(L',',j) + 1;
					t.kiaiMode			= _wtoi(&buffer[j]);
					timingPoints.push_back(t);
				}
			break;
			case Colours:
				{
					Color c;
					int												j = buffer.find_first_of(L':',0) + 1;
					c.R	= _wtoi(&buffer[j]);					j = buffer.find_first_of(L',',j) + 1;
					c.G	= _wtoi(&buffer[j]);					j = buffer.find_first_of(L',',j) + 1;
					c.B	= _wtoi(&buffer[j]);
					c.A	= 255;
					comboColors.push_back(c);
				}
			break;
			case HitObjects:
				{
					HitObject hit;
					int j = 0, j2;
					hit.x			= _wtoi(&buffer[j]);			j = buffer.find_first_of(L',',j) + 1;
					hit.y			= _wtoi(&buffer[j]);			j = buffer.find_first_of(L',',j) + 1;
					hit.time		= _wtoi(&buffer[j]);			j = buffer.find_first_of(L',',j) + 1;
					hit.type		= _wtoi(&buffer[j]);			j = buffer.find_first_of(L',',j) + 1;
					hit.sound	= _wtoi(&buffer[j]);			j = buffer.find_first_of(L',',j) + 1;
					if(hit.type&SPINNER)
						hit.stop = _wtoi(&buffer[j]);
					if(hit.type&SLIDER)
					{
						POINT p;
						hit.points.resize(0);
						hit.interpolationType = buffer[j];	j2= buffer.find_first_of(L',',j);
						while(true)
						{												j = buffer.find_first_of(L'|',j) + 1;
							if(j-1==std::wstring::npos || j>=j2)
								break;
							p.x	= _wtoi(&buffer[j]);			j = buffer.find_first_of(L':',j) + 1;
							p.y	= _wtoi(&buffer[j]);
							hit.points.push_back(p);
						}
																		j = j2 + 1;
						hit.count = _wtoi(&buffer[j]);		j = buffer.find_first_of(L',',j) + 1;
						hit.stop  = _wtoi(&buffer[j]);	// TODO: figure out what rare cases with remaining stuff, like "4|0" or "4|4" mean
					}
					else
					{
						hit.count = 
						hit.stop  = 0;
					}

					hitObjects.push_back(hit);
				}
			break;
		}

	}//until eof

	file.close();

	return;
}


